package yf.mall.component.helper;

import com.yf.utils.DateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import yf.mall.common.Const;
import yf.mall.dysdk.model.DyKolOrder;
import yf.mall.entity.DyAccountAuthEntity;
import yf.mall.entity.KolOrderEntity;
import yf.mall.entity.KolOrderStatEntity;
import yf.mall.enums.KolOrderFlowPointEnum;
import yf.mall.enums.app.AppOrderDateTypeEnum;
import yf.mall.enums.app.AppTimeTypeEnum;
import yf.mall.utils.CustomBeanCopier;
import yf.mall.utils.app.AppDateUtil;
import yf.mall.utils.app.AppUtil;
import yf.mall.vo.app.order.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yxmds
 */
public final class OrderHelper {

    private OrderHelper() {
    }

    public static KolOrderVo convert(KolOrderEntity entity) {
        KolOrderVo kolOrderVo = new KolOrderVo();
        kolOrderVo.setOrderId(entity.getId().toString());
        kolOrderVo.setCover(entity.getProductImg());
        kolOrderVo.setFlowPoint(entity.getFlowPoint());
        kolOrderVo.setAuthorOpenid(entity.getAuthorOpenid());
        kolOrderVo.setAuthorAccount(entity.getAuthorAccount());
        kolOrderVo.setFlowPointStr(KolOrderFlowPointEnum.indexOf(entity.getFlowPoint()));
        kolOrderVo.setKolCosFee(String.valueOf(BigDecimal.valueOf(entity.getEstimatedTotalCommission()).divide(Const.HUNDRED, 2, RoundingMode.HALF_DOWN)));
        kolOrderVo.setKolCosRatio(String.valueOf(BigDecimal.valueOf(entity.getCommissionRate()).divide(Const.HUNDRED, 2, RoundingMode.HALF_DOWN)));
        kolOrderVo.setPaySuccessTime(DateUtil.dateToStr(entity.getPaySuccessTime()));
        kolOrderVo.setPid(entity.getProductId().toString());
        kolOrderVo.setTitle(entity.getProductName());
        kolOrderVo.setTotalPayAmount(String.valueOf(BigDecimal.valueOf(entity.getTotalPayAmount()).divide(Const.HUNDRED, 2, RoundingMode.HALF_DOWN)));
        kolOrderVo.setShopId(entity.getShopId().toString());
        kolOrderVo.setShopName(entity.getShopName());
        return kolOrderVo;
    }

    public static KolOrderEntity convertDyToDb(DyKolOrder order) {
        KolOrderEntity kolOrderEntity = new KolOrderEntity();
        kolOrderEntity.setId(order.getOrderId());
        kolOrderEntity.setProductId(order.getProductId());
        kolOrderEntity.setProductName(order.getProductName());
        kolOrderEntity.setProductImg(order.getProductImg());
        kolOrderEntity.setAuthorAccount(order.getAuthorAccount());
        kolOrderEntity.setAuthorOpenid(order.getAuthorOpenid());
        kolOrderEntity.setShopName(order.getShopName());
        kolOrderEntity.setTotalPayAmount(order.getTotalPayAmount());
        kolOrderEntity.setCommissionRate(Long.valueOf(order.getCommissionRate()));
        kolOrderEntity.setFlowPoint(order.getFlowPoint());
        kolOrderEntity.setApp(order.getApp());
        kolOrderEntity.setUpdateTime(order.getUpdateTime());
        kolOrderEntity.setPaySuccessTime(order.getPaySuccessTime());
        kolOrderEntity.setSettleTime(order.getSettleTime());
        kolOrderEntity.setPayGoodsAmount(Long.valueOf(order.getPayGoodsAmount()));
        kolOrderEntity.setSettledGoodsAmount(order.getSettledGoodsAmount());
        kolOrderEntity.setEstimatedCommission(order.getEstimatedCommission());
        kolOrderEntity.setRealCommission(order.getRealCommission());
        kolOrderEntity.setExtra(ObjectUtils.defaultIfNull(order.getExtra(), ""));
        kolOrderEntity.setItemNum(order.getItemNum());
        kolOrderEntity.setShopId(order.getShopId());
        kolOrderEntity.setRefundTime(ObjectUtils.defaultIfNull(order.getRefundTime(), DateUtil.firstDayOfMonth(1970, 1)));
        kolOrderEntity.setEstimatedTotalCommission(order.getEstimatedTotalCommission());
        kolOrderEntity.setEstimatedTechServiceFee(order.getEstimatedTechServiceFee());
        kolOrderEntity.setPickSourceClientKey(ObjectUtils.defaultIfNull(order.getPickSourceClientKey(), ""));
        kolOrderEntity.setPickExtra(ObjectUtils.defaultIfNull(order.getPickExtra(), ""));
        kolOrderEntity.setAuthorShortId(order.getAuthorShortId());
        kolOrderEntity.setMediaType(order.getMediaType());
        return kolOrderEntity;
    }

    public static KolOrderStatVo convertOrderToStat(List<KolOrderEntity> orders) {
        List<KolOrderEntity> validOrders = orders.stream().filter(order -> Arrays.asList(KolOrderFlowPointEnum.SETTLE.getIndex(), KolOrderFlowPointEnum.CONFIRM.getIndex(), KolOrderFlowPointEnum.PAY_SUCC.getIndex()).contains(order.getFlowPoint())).collect(Collectors.toList());
        List<KolOrderEntity> refundOrders = orders.stream().filter(order -> Objects.equals(KolOrderFlowPointEnum.REFUND.getIndex(), order.getFlowPoint())).collect(Collectors.toList());
        KolOrderStatVo kolOrderStatVo = new KolOrderStatVo();
        kolOrderStatVo.setEstimatedCommission(AppUtil.getNumberStrToWan(calEstimatedCommission(orders), 2));
        kolOrderStatVo.setOrderCount(orders.size());
        kolOrderStatVo.setRefundEstimatedCommission(AppUtil.getNumberStrToWan(calEstimatedCommission(refundOrders), 2));
        kolOrderStatVo.setRefundOrderCount(refundOrders.size());
        kolOrderStatVo.setRefundPayAmount(AppUtil.getNumberStrToWan(calPayAmount(refundOrders), 2));
        if (orders.size() == 0) {
            kolOrderStatVo.setRefundRatio("0");
        } else {
            kolOrderStatVo.setRefundRatio(BigDecimal.valueOf(refundOrders.size()).divide(BigDecimal.valueOf(orders.size()), 2, RoundingMode.HALF_DOWN).toString());
        }
        kolOrderStatVo.setTotalPayAmount(AppUtil.getNumberStrToWan(calPayAmount(orders), 2));
        kolOrderStatVo.setValidEstimatedCommission(AppUtil.getNumberStrToWan(calEstimatedCommission(validOrders), 2));
        kolOrderStatVo.setValidOrderCount(validOrders.size());
        kolOrderStatVo.setValidPayAmount(AppUtil.getNumberStrToWan(calPayAmount(validOrders), 2));
        return kolOrderStatVo;
    }

    public static KolOrderStatEntity convertOrderToStatEntity(List<KolOrderEntity> orders) {
        if (CollectionUtils.isEmpty(orders)) {
            return null;
        }
        List<KolOrderEntity> validOrders = orders.stream().filter(order -> Objects.equals(KolOrderFlowPointEnum.SETTLE.getIndex(), order.getFlowPoint())).collect(Collectors.toList());
        List<KolOrderEntity> refundOrders = orders.stream().filter(order -> Objects.equals(KolOrderFlowPointEnum.REFUND.getIndex(), order.getFlowPoint())).collect(Collectors.toList());
        KolOrderStatEntity kolOrderStatEntity = new KolOrderStatEntity();
        kolOrderStatEntity.setEstimatedCommission(calEstimatedCommission(orders));
        kolOrderStatEntity.setOrderCount(BigDecimal.valueOf(orders.size()));
        kolOrderStatEntity.setRefundEstimatedCommission(calEstimatedCommission(refundOrders));
        kolOrderStatEntity.setRefundOrderCount(BigDecimal.valueOf(refundOrders.size()));
        kolOrderStatEntity.setRefundPayAmount(calPayAmount(refundOrders));
        if (orders.size() == 0) {
            kolOrderStatEntity.setRefundRatio(BigDecimal.ZERO);
        } else {
            kolOrderStatEntity.setRefundRatio(BigDecimal.valueOf(refundOrders.size()).divide(BigDecimal.valueOf(orders.size()), 2, RoundingMode.HALF_DOWN));
        }
        kolOrderStatEntity.setTotalPayAmount(calPayAmount(orders));
        kolOrderStatEntity.setValidEstimatedCommission(calEstimatedCommission(validOrders));
        kolOrderStatEntity.setValidOrderCount(BigDecimal.valueOf(validOrders.size()));
        kolOrderStatEntity.setValidPayAmount(calPayAmount(validOrders));
        return kolOrderStatEntity;
    }

    private static BigDecimal calEstimatedCommission(List<KolOrderEntity> dyKolOrders) {
        return dyKolOrders.stream().map(order -> BigDecimal.valueOf(ObjectUtils.defaultIfNull(order.getEstimatedTotalCommission(), 0L)).divide(Const.HUNDRED, 2, RoundingMode.DOWN)).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private static BigDecimal calPayAmount(List<KolOrderEntity> dyKolOrders) {
        return dyKolOrders.stream().map(order -> BigDecimal.valueOf(order.getTotalPayAmount()).divide(Const.HUNDRED, 2, RoundingMode.DOWN)).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public static List<KolOrderStatByTimeVo> convertOrderToStatByTime(List<KolOrderEntity> userOrders, Integer dateType, Integer timeType) {
        if (Objects.equals(AppOrderDateTypeEnum.PAY_TIME.getType(), dateType)) {
            return convertOrderToStatByPayTime(userOrders, timeType);
        } else if (Objects.equals(AppOrderDateTypeEnum.SETTLE_TIME.getType(), dateType)) {
            return convertOrderToStatBySettleTime(userOrders, timeType);
        }
        return Collections.emptyList();
    }

    public static List<KolOrderStatByTimeVo> convertOrderToStatByPayTime(List<KolOrderEntity> orders, Integer timeType) {
        Map<LocalDateTime, List<KolOrderEntity>> groupedOrders = orders.stream().collect(Collectors.groupingBy(order -> AppDateUtil.groupOrderByTime(timeType, order.getPaySuccessTime())));
        return convertGroupMapToOrderStat(groupedOrders, timeType);
    }


    public static List<KolOrderStatByTimeVo> convertOrderToStatBySettleTime(List<KolOrderEntity> orders, Integer timeType) {
        Map<LocalDateTime, List<KolOrderEntity>> groupedOrders = orders.stream().collect(Collectors.groupingBy(order -> AppDateUtil.groupOrderByTime(timeType, order.getSettleTime())));
        return convertGroupMapToOrderStat(groupedOrders, timeType);
    }


    public static List<KolOrderStatByUserVo> convertOrderToStatByUser(List<DyAccountAuthEntity> allAuth, List<KolOrderEntity> orders) {
        Map<String, DyAccountAuthEntity> authMap = allAuth.stream().collect(Collectors.toMap(DyAccountAuthEntity::getOpenId, Function.identity()));
        Map<String, List<KolOrderEntity>> groupedOrders = orders.stream().collect(Collectors.groupingBy(order -> order.getAuthorOpenid()));
        return groupedOrders.entrySet().stream().map(entry -> {
            KolOrderStatByUserVo kolOrderStatByUserVo = CustomBeanCopier.copy(OrderHelper.convertOrderToStat(entry.getValue()), KolOrderStatByUserVo.class);
            DyAccountAuthEntity dyAccountAuthEntity = authMap.get(entry.getKey());
            if (dyAccountAuthEntity == null) {
                return null;
            }
            kolOrderStatByUserVo.setDisplayId(dyAccountAuthEntity.getUid());
            kolOrderStatByUserVo.setAvatar(dyAccountAuthEntity.getAvatar());
            kolOrderStatByUserVo.setNickName(dyAccountAuthEntity.getName());
            return kolOrderStatByUserVo;
        }).filter(Objects::nonNull).sorted(Comparator.comparing(o -> new BigDecimal(o.getTotalPayAmount()))).collect(Collectors.toList());
    }

    private static List<KolOrderStatByTimeVo> convertGroupMapToOrderStat(Map<LocalDateTime, List<KolOrderEntity>> groupedOrders, Integer timeType) {
        return groupedOrders.entrySet().stream().map(entry -> {
            KolOrderStatByTimeVo kolOrderStatByTimeVo = CustomBeanCopier.copy(OrderHelper.convertOrderToStat(entry.getValue()), KolOrderStatByTimeVo.class);
            kolOrderStatByTimeVo.setLocalDateTime(entry.getKey());
            if (timeType == null) {
                kolOrderStatByTimeVo.setTime(entry.getKey().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            } else {
                kolOrderStatByTimeVo.setTime(entry.getKey().format(DateTimeFormatter.ofPattern("HH:mm")));
            }
            return kolOrderStatByTimeVo;
        }).sorted(Comparator.comparing(KolOrderStatByTimeVo::getLocalDateTime)).collect(Collectors.toList());
    }

    public static List<KolOrderVo> orderEntityListToVo(List<KolOrderEntity> orderEntityList) {
        return orderEntityList.stream().map(OrderHelper::convert).collect(Collectors.toList());
    }

    public static void fillUserInfo(List<KolOrderVo> orderVos, List<DyAccountAuthEntity> allAuthByUser) {
        Map<String, DyAccountAuthEntity> userMap = allAuthByUser.stream().collect(Collectors.toMap(DyAccountAuthEntity::getOpenId, Function.identity()));
        for (KolOrderVo kolOrderVo : orderVos) {
            if (userMap.containsKey(kolOrderVo.getAuthorOpenid())) {
                DyAccountAuthEntity user = userMap.get(kolOrderVo.getAuthorOpenid());
                kolOrderVo.setAuthorAvatar(user.getAvatar());
                kolOrderVo.setAuthorUid(user.getUid());
            }
        }
    }
}
